#include "TextureLibrary.hpp"

std::map<std::string, Texture*> m_cache;

Texture::Texture( std::string name )
: filename( name ),
  m_isInUse( false ),
  m_isLoaded( false ),
  m_useMipMaps( true )
{
}

void Texture::setUseMipMaps( bool mip )
{
	if( m_isLoaded )
        Logger::write( "Texture", "setUseMipMaps( bool )",
                       "Cannot change mip map type when texture is loaded.", Logger::Error );
	else
		m_useMipMaps = mip;
}

void Texture::bind()
{
	glEnable( GL_TEXTURE_2D );
	m_isInUse = true;
	glBindTexture( GL_TEXTURE_2D, glId );
}

void Texture::unbind()
{
	m_isInUse = false;
    glBindTexture( GL_TEXTURE_2D, (GLuint)NULL );
}


Texture* getTexture( std::string filename )
{  
    Texture* texture;

    std::map<std::string, Texture*>::iterator found = m_cache.find( filename );
    if( found != m_cache.end() )
    {
        // Texture object exists, but may not be loaded yet.
        texture = found->second;
        if( texture->isLoaded() )
        {
            Logger::write( "Texture", "getTexture( string )",
                           QString( "\"" ) + filename.c_str() +
                           QString( "\" already loaded" ),
                           Logger::Note );
            return texture;
        }
    } else {
        // Texture does not yet exist
        texture = new Texture( filename );
    }

    QImage b;
    
    if ( !b.load( filename.c_str() ) )
    {
        Logger::write( "Texture", "getTexture( string )",
                       QString( "\"" ) + filename.c_str() +
                       QString( "\" not loaded" ),
                       Logger::Error );
        b = QImage( 16, 16, QImage::Format_RGB16 );
        b.fill( Qt::green );
    }
    else {
        Logger::write( "Texture", "getTexture( string )",
                       QString( "\"" ) + filename.c_str() +
                       QString( "\" successfully loaded" ),
                       Logger::Note );
    }
    
    texture->image = QGLWidget::convertToGLFormat( b );
    glGenTextures( 1, &texture->glId );
    glBindTexture( GL_TEXTURE_2D, texture->glId );


    if( texture->usesMipMaps() )
    {
        gluBuild2DMipmaps( GL_TEXTURE_2D, 3, texture->image.width(), texture->image.height(),
                           GL_RGBA, GL_UNSIGNED_BYTE, texture->image.bits() );
        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                         GL_LINEAR_MIPMAP_NEAREST );

    } else {
        glTexImage2D( GL_TEXTURE_2D, 0, 3, texture->image.width(), texture->image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, texture->image.bits() );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    }

    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );


    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );

    gluBuild2DMipmaps( GL_TEXTURE_2D, 3, texture->image.width(), texture->image.height(),
                       GL_RGBA, GL_UNSIGNED_BYTE, texture->image.bits() );

    texture->setLoaded( true );
    m_cache[ filename ] = texture;

    return texture;
}
